﻿namespace Microsoft.VisualStudio.ServiceModel.DomainServices.Tools
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Globalization;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.Remoting;
    using System.Threading;
    using System.Web.Compilation;

    internal class BusinessLogicViewModel : INotifyPropertyChanged, IDisposable
    {
        private string _assemblyName;
        private Microsoft.VisualStudio.ServiceModel.DomainServices.Tools.BusinessLogicModel _businessLogicModel;
        private string _className;
        private System.Web.Compilation.ClientBuildManager _clientBuildManager;
        private List<Type> _contextTypes;
        private List<ContextViewModel> _contextViewModels;
        private ContextViewModel _currentContextViewModel;
        private bool _generateMetadataClasses;
        private IVsHelp _help;
        private string _language;
        private string _projectDirectory;
        private string _rootNamespace;

        public event PropertyChangedEventHandler PropertyChanged;

        public BusinessLogicViewModel(string projectDirectory, string className, string language, string rootNamespace, string assemblyName, IEnumerable<Type> contextTypes, IVsHelp help)
        {
            if (string.IsNullOrEmpty(projectDirectory))
            {
                throw new ArgumentNullException("projectDirectory");
            }
            if (string.IsNullOrEmpty(className))
            {
                throw new ArgumentNullException("className");
            }
            if (string.IsNullOrEmpty(language))
            {
                throw new ArgumentNullException("language");
            }
            if (contextTypes == null)
            {
                throw new ArgumentNullException("contextTypes");
            }
            if (string.IsNullOrEmpty(assemblyName))
            {
                throw new ArgumentNullException("assemblyName");
            }
            this._projectDirectory = projectDirectory;
            this._className = className;
            this._language = language;
            this._rootNamespace = rootNamespace;
            this._assemblyName = assemblyName;
            this._contextTypes = new List<Type>(contextTypes);
            this._help = help;
        }

        private void CurrentContextPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
        {
            string propertyName = propertyChangedEventArgs.PropertyName;
            if (string.Equals(propertyName, "IsMetadataClassGenerationAllowed", StringComparison.OrdinalIgnoreCase))
            {
                this.RaisePropertyChanged(propertyName);
            }
        }

        public void DisplayHelp()
        {
            if (this._help != null)
            {
                this._help.DisplayTopicFromF1Keyword("DomainServiceWizard.UI");
            }
        }

        public void Dispose()
        {
            GC.SuppressFinalize(this);
            if (this._businessLogicModel != null)
            {
                try
                {
                    this._businessLogicModel.Dispose();
                }
                catch (RemotingException)
                {
                }
                this._businessLogicModel = null;
            }
            IDisposable disposable = this._clientBuildManager;
            if (disposable != null)
            {
                disposable.Dispose();
            }
            this._clientBuildManager = null;
        }

        public GeneratedCode GenerateBusinessLogicClass(string namespaceName)
        {
            ContextViewModel currentContextViewModel = this.CurrentContextViewModel;
            if (currentContextViewModel != null)
            {
                return this.BusinessLogicModel.GenerateBusinessLogicClass(currentContextViewModel.ContextData, this.ClassName, namespaceName, this.RootNamespace);
            }
            return new GeneratedCode();
        }

        public GeneratedCode GenerateMetadataClasses(string optionalSuffix)
        {
            ContextViewModel currentContextViewModel = this.CurrentContextViewModel;
            if (currentContextViewModel != null)
            {
                return this.BusinessLogicModel.GenerateMetadataClasses(currentContextViewModel.ContextData, this.RootNamespace, optionalSuffix);
            }
            return new GeneratedCode(string.Empty, new string[0]);
        }

        private void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private void ReportException(Exception exception)
        {
            Action<Exception> exceptionHandler = this.ExceptionHandler;
            if (exceptionHandler == null)
            {
                throw exception;
            }
            exceptionHandler(exception);
        }

        private void ValidateClassName(string className)
        {
            using (CodeGenContext context = new CodeGenContext(this.Language, this.RootNamespace))
            {
                if (string.IsNullOrEmpty(className) || !context.IsValidIdentifier(className))
                {
                    this.ReportException(new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_Error_Invalid_ClassName, new object[] { className })));
                }
            }
        }

        internal string AssemblyName
        {
            get
            {
                return this._assemblyName;
            }
        }

        private Microsoft.VisualStudio.ServiceModel.DomainServices.Tools.BusinessLogicModel BusinessLogicModel
        {
            get
            {
                if (this._businessLogicModel == null)
                {
                    this._businessLogicModel = (Microsoft.VisualStudio.ServiceModel.DomainServices.Tools.BusinessLogicModel) this.ClientBuildManager.CreateObject(typeof(Microsoft.VisualStudio.ServiceModel.DomainServices.Tools.BusinessLogicModel), false);
                    HashSet<string> source = new HashSet<string>();
                    HashSet<string> set2 = new HashSet<string>();
                    List<string> list = new List<string>();
                    foreach (Type type in this._contextTypes)
                    {
                        if (CodeGenUtilities.IsValidGenericTypeParam(type))
                        {
                            source.Add(type.Assembly.Location);
                            list.Add(type.AssemblyQualifiedName);
                            Action<string> logger = delegate (string s) {
                            };
                            foreach (Assembly assembly in AssemblyUtilities.GetReferencedAssemblies(type.Assembly, logger))
                            {
                                if (!source.Contains(assembly.Location))
                                {
                                    set2.Add(assembly.Location);
                                }
                            }
                        }
                    }
                    BusinessLogicData data2 = new BusinessLogicData {
                        Language = this.Language,
                        AssemblyPaths = source.ToArray<string>(),
                        ReferenceAssemblyPaths = set2.ToArray<string>(),
                        ContextTypeNames = list.ToArray(),
                        LinqToSqlPath = LinqToSqlContext.LinqToSqlDomainServiceAssemblyPath
                    };
                    BusinessLogicData businessLogicData = data2;
                    this._businessLogicModel.Initialize(businessLogicData);
                }
                return this._businessLogicModel;
            }
        }

        public string ClassName
        {
            get
            {
                return this._className;
            }
            set
            {
                this.ValidateClassName(value);
                if (this._className != value)
                {
                    this._className = value;
                    this.RaisePropertyChanged("ClassName");
                }
            }
        }

        private System.Web.Compilation.ClientBuildManager ClientBuildManager
        {
            get
            {
                if (this._clientBuildManager == null)
                {
                    this._clientBuildManager = new System.Web.Compilation.ClientBuildManager("/", this.ProjectDirectory, null, null);
                }
                return this._clientBuildManager;
            }
        }

        public IList<ContextViewModel> ContextViewModels
        {
            get
            {
                if (this._contextViewModels == null)
                {
                    this._contextViewModels = new List<ContextViewModel>();
                    foreach (ContextData data in from c in this.BusinessLogicModel.GetContextDataItems()
                        orderby c.Name
                        select c)
                    {
                        this._contextViewModels.Add(new ContextViewModel(this.BusinessLogicModel, data));
                    }
                }
                return this._contextViewModels;
            }
        }

        public ContextViewModel CurrentContextViewModel
        {
            get
            {
                if (this._currentContextViewModel == null)
                {
                    IList<ContextViewModel> contextViewModels = this.ContextViewModels;
                    if (contextViewModels.Count == 1)
                    {
                        this.CurrentContextViewModel = contextViewModels[0];
                    }
                    else if (contextViewModels.Count > 1)
                    {
                        this.CurrentContextViewModel = contextViewModels[1];
                    }
                }
                return this._currentContextViewModel;
            }
            set
            {
                if (value != this._currentContextViewModel)
                {
                    if (this._currentContextViewModel != null)
                    {
                        this._currentContextViewModel.PropertyChanged -= new PropertyChangedEventHandler(this.CurrentContextPropertyChanged);
                    }
                    this._currentContextViewModel = value;
                    if (this._currentContextViewModel != null)
                    {
                        this._currentContextViewModel.PropertyChanged += new PropertyChangedEventHandler(this.CurrentContextPropertyChanged);
                    }
                    this.RaisePropertyChanged("CurrentContextViewModel");
                    this.RaisePropertyChanged("IsMetadataClassGenerationRequested");
                    this.RaisePropertyChanged("IsMetadataClassGenerationAllowed");
                }
            }
        }

        public Action<Exception> ExceptionHandler { get; set; }

        public bool IsMetadataClassGenerationAllowed
        {
            get
            {
                ContextViewModel currentContextViewModel = this.CurrentContextViewModel;
                if (currentContextViewModel == null)
                {
                    return false;
                }
                if (!this.BusinessLogicModel.IsMetadataGenerationRequired(currentContextViewModel.ContextData))
                {
                    return false;
                }
                IEnumerable<EntityViewModel> source = from e in currentContextViewModel.Entities
                    where e.IsIncluded
                    select e;
                if (!source.Any<EntityViewModel>())
                {
                    return false;
                }
                foreach (EntityViewModel model2 in source)
                {
                    string assemblyName = model2.EntityData.AssemblyName;
                    if (!string.Equals(this.AssemblyName, assemblyName, StringComparison.OrdinalIgnoreCase))
                    {
                        return false;
                    }
                }
                return true;
            }
        }

        public bool IsMetadataClassGenerationRequested
        {
            get
            {
                return (this._generateMetadataClasses && this.IsMetadataClassGenerationAllowed);
            }
            set
            {
                if (!((this.CurrentContextViewModel != null) && this.IsMetadataClassGenerationAllowed))
                {
                    value = false;
                }
                if (this._generateMetadataClasses != value)
                {
                    this._generateMetadataClasses = value;
                    this.RaisePropertyChanged("IsMetadataClassGenerationRequested");
                    this.RaisePropertyChanged("IsMetadataClassGenerationAllowed");
                }
            }
        }

        internal string Language
        {
            get
            {
                return this._language;
            }
        }

        public string ProjectDirectory
        {
            get
            {
                return this._projectDirectory;
            }
        }

        internal string RootNamespace
        {
            get
            {
                return this._rootNamespace;
            }
        }
    }
}

